package com.jinke.api.security.component;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jinke.api.common.util.CommonUtil;
import com.jinke.api.config.JacksonAutoConfiguration;
import com.jinke.api.modules.app.enums.Roles;
import com.jinke.api.modules.third.ezeeship.util.EzeeShipUtil;
import com.jinke.api.modules.ums.model.UmsAdmin;
import com.jinke.api.modules.ums.model.UmsAdminLog;
import com.jinke.api.modules.ums.model.UmsRole;
import com.jinke.api.modules.ums.service.UmsAdminLogService;
import com.jinke.api.modules.ums.service.UmsAdminService;
import com.jinke.api.security.util.AdminUserUtil;
import com.jinke.api.security.util.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;

/**
 * JWT登录授权过滤器
 * Created by macro on 2018/4/26.
 */
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationTokenFilter.class);
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Value("${jwt.tokenHeader}")
    private String tokenHeader;
    @Value("${jwt.tokenHead}")
    private String tokenHead;

    private ObjectMapper om = JacksonAutoConfiguration.jacksonObject();

    @Resource
    private UmsAdminService umsAdminService;
    @Autowired
    private UmsAdminLogService umsAdminLogService;
    // private final CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        String authHeader = request.getHeader(this.tokenHeader);

        // 接收选择的语言
        Locale userLocale = request.getLocale();

        if (authHeader != null && authHeader.startsWith(this.tokenHead)) {
            String authToken = authHeader.substring(this.tokenHead.length());// The part after "Bearer "
            String username = jwtTokenUtil.getUserNameFromToken(authToken);
            LOGGER.info("checking username:{}", username);
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
                if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    LOGGER.info("authenticated user:{}", username);
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                    setThreadUserInfo(username, userLocale);
                }
            }
        }

        // todo: 看看是不是只需要记录管理相关的接口，不然用户请求全都会记录 @memory


        String payload = request.getQueryString();
        String method = request.getMethod();
        ResponseWrapper responseWrapper = new ResponseWrapper(response);
        if (method.equals("POST")) {
            if (isMultipartContent(request)) {
                // 处理Multipart请求（包含文件上传）
                // MultipartHttpServletRequest multipartRequest = multipartResolver.resolveMultipart(request);
                chain.doFilter(request, responseWrapper);
            } else {
                // 处理普通表单数据
                RequestWrapper requestWrapper = new RequestWrapper(request);
                chain.doFilter(requestWrapper, responseWrapper);
                payload = requestWrapper.getBody();
                //chain.doFilter(requestWrapper, responseWrapper);
            }
        } else {
            RequestWrapper requestWrapper = new RequestWrapper(request);
            chain.doFilter(requestWrapper, responseWrapper);
        }

        try {
            if (AdminUserUtil.getUserInfo() != null && (method.equals("POST") || method.equals("GET"))) {
                String userAgent = request.getHeader("User-Agent");
                String ip = getIpAddr(request);
                Integer adminId = AdminUserUtil.getUserId();
                if (payload == null) {
                    payload = "";
                }
                String code = "-1";
                String message = "unknown";
                String header = response.getHeader("Content-Type");
                if ("application/octet-stream".equals(header)) {
                    return;
                }
                if ("application/zip".equals(header)) {
                    return;
                }
                JsonNode jsonNode = om.readTree(responseWrapper.toByteArray());
                if (jsonNode != null && jsonNode.get("code") != null) {
                    code = jsonNode.get("code").asText("-1");
                    if (code.equals("-1")) {
                        code = String.valueOf(jsonNode.get("code").intValue());
                    }
                    if (jsonNode.get("message") != null) {
                        message = jsonNode.get("message").asText("unknown");
                    }
                }

                UmsAdminLog log = new UmsAdminLog();
                String orderNo = CommonUtil.getOrderNo();
                log.setAdminId(adminId.longValue())
                        .setIp(ip)
                        .setUsername(AdminUserUtil.getUserInfo().getUsername())
                        .setUserAgent(orderNo)
                        .setMessage(message)
                        .setMethod(request.getMethod())
                        .setUri(request.getRequestURI())
                        .setStatusCode(Integer.parseInt((code)))
                        .setParams(payload);


                logger.info("orderNo-"+orderNo + " 请求路径-" + request.getRequestURI() + "参数- " + payload+ "msg-"+message);

                if (jsonNode != null) {
                    logger.debug(orderNo + " " + jsonNode.toString());
                }
                umsAdminLogService.save(log);

                if (StringUtils.isNotBlank(authHeader)) {
                    String refreshToken = umsAdminService.refreshToken(authHeader);
                    if (!("Bearer " + refreshToken).equals(authHeader)) {
                        response.setHeader("token", refreshToken);
                    }

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            AdminUserUtil.clean();
        }
    }

    private void setThreadUserInfo(String username, Locale userLocale) {
        UmsAdmin admin = umsAdminService.getAdminByKeyword(username);
        List<UmsRole> roleList = umsAdminService.getRoleList(admin.getId());
        if (CollUtil.isNotEmpty(roleList)) {
            List<Integer> roles = roleList.stream().map(x -> {
                return x.getId();
            }).collect(Collectors.toList());
            admin.setSeller(roles.contains(Roles.SALES.getValue()));
            admin.setAdmin(roles.contains(Roles.ADMIN.getValue()));
        }
        // 设置用户语言
        admin.setUserLocale(userLocale);
        AdminUserUtil.setUserInfo(admin);
    }

    public boolean isMultipartContent(HttpServletRequest request) {
        try {
            return ServletFileUpload.isMultipartContent(request);
        } catch (Exception e) {
            return false;
        }
    }

    public static String getIpAddr(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        } else {
            String ip = request.getHeader("x-forwarded-for");
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }

            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("X-Forwarded-For");
            }

            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }

            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("X-Real-IP");
            }

            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }

            if (StringUtils.isNotEmpty(ip) && ip.contains(",")) {
                ip = ip.split(",")[0];
            }

            return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
        }
    }
}
